package com.etocrm.saas.lib.base.server.json;

import cn.hutool.core.util.ReflectUtil;
import com.etocrm.saas.lib.base.common.enums.base.BaseEnum;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

/**
 * jackson baseEnum 序列化器
 * <p>
 * 所有的枚举输出统一对前端输出 : 字段内包含json对象 {enumCode : code , enumDesc : desc}
 * Created by Xs on 2022/11/15.
 */
@Slf4j
public class JacksonBaseEnumSerializer {
    public static final String ENUM_CODE_KEY = "enumCode";
    public static final String ENUM_DESC_KEY = "enumDesc";

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer enumCustomizer() {

        return jacksonObjectMapperBuilder -> {
            jacksonObjectMapperBuilder.serializerByType(Enum.class, new JsonSerializer<Enum>() {
                @Override
                public void serialize(Enum anEnum, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                    if (BaseEnum.class.isAssignableFrom(anEnum.getClass())) {
                        BaseEnum baseEnum = (BaseEnum) anEnum;
                        jsonGenerator.writeStartObject();
                        jsonGenerator.writeStringField(ENUM_CODE_KEY, String.valueOf(baseEnum.getValue()));
                        jsonGenerator.writeStringField(ENUM_DESC_KEY, baseEnum.getDesc());
                        jsonGenerator.writeEndObject();
                    } else {
                        log.error("不支持枚举类型 : {}", anEnum.getClass());
                        throw new RuntimeException("不支持枚举类型.");
                    }
                }
            });


            jacksonObjectMapperBuilder.deserializerByType(Enum.class, new JsonDeserializer<Enum>() {

                @Override
                public Enum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                    JsonNode jsonNode = deserializationContext.readTree(jsonParser);
                    JsonNodeType nodeType = jsonNode.getNodeType();
                    int enumCode;

                    if (Objects.equals(nodeType, JsonNodeType.NUMBER)) {
                        enumCode = jsonNode.asInt();
                    } else if (Objects.equals(nodeType, JsonNodeType.OBJECT)) {
                        enumCode = jsonNode.get(ENUM_CODE_KEY).asInt();
                    } else {
                        log.warn("不支持的枚举序列化方式 , nodeType不兼容, nodeType: {}", nodeType);
                        return null;
                    }

                    String fieldName = jsonParser.getParsingContext().getCurrentName();
                    Class<?> FieldType = jsonParser.getParsingContext().getCurrentValue().getClass();
                    Class<?> enumType = ReflectUtil.getField(FieldType, fieldName).getType();
                    
                    if (BaseEnum.class.isAssignableFrom(enumType)) {
                        return (Enum) Arrays.stream(enumType.getEnumConstants()).filter(c -> Objects.equals(((BaseEnum) c).getValue(), enumCode)).findFirst().orElse(null);
                    } else {
                        log.warn("不支持序列化的枚举类型, 未实现BaseEnum接口  enumType : {}", enumType);
                        return null;
                    }
                }
            });
        };
    }
}
